/**********************************************************************
 *
 * This code is developed for the course Informatica Industrial II
 * of Universidad Carlos III de Madrid - 2012
 * Authors: Victor González-Pacheco, Alberto Valero-Gomez
 *
 * The code is licenced under the Common Creative License,
 * Attribution-ShareAlike 3.0
 *
 * You are free:
 *   - to Share - to copy, distribute and transmit the work
 *   - to Remix - to adapt the work
 *
 * Under the following conditions:
 *   - Attribution. You must attribute the work in the manner specified
 *     by the author or licensor (but not in any way that suggests that
 *     they endorse you or your use of the work).
 *   - Share Alike. If you alter, transform, or build upon this work,
 *     you may distribute the resulting work only under the same or
 *     similar license to this one.
 *
 * Any of the above conditions can be waived if you get permission
 * from the copyright holder.  Nothing in this license impairs or
 * restricts the author's moral rights.
 *
 * It is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.
 **********************************************************************/


#ifndef ABSTRACTSOCKET__H
#define ABSTRACTSOCKET__H

#include <iostream>
using namespace std;

/**
  * \brief Abstract Socket Client Class
  * This class implements a Abstract Socket Class using the paradigm os streams
  */
class AbstractSocket : public iostream{
public:

    /**
     * @brief Default copy constructor
     * @param other
     */
    AbstractSocket(const AbstractSocket& other):
        _ip(other._ip),
        _port(other._port),
        _local_ip(other._local_ip),
        _local_port(other._local_port),
        _socket_fd(other._socket_fd)
    {
    }

    virtual ~AbstractSocket(){
       // close();
    }

    /**
      * \brief sends a string though the socket connection
      * << Operator overloaded to send a string though the socket connection
      * \param cad string to send
      */
    AbstractSocket & operator << (const string & cad) throw (char const *);
    AbstractSocket & operator <<(char const* cad) throw (char const *);

    /**
      * \brief reads a string though the socket connection
      * >> Operator overloaded to send a string though the socket connection
      * \param cad string to store the received data
      */
    AbstractSocket & operator >>(string & cad) throw (char const *);

    inline void setRemoteIP(string ip){_ip = ip;}
    inline void setRemotePort(int port){_port = port;}

    inline void setLocalIP(string ip){_local_ip = ip;}
    inline void setLocalPort(int port){_local_port = port;}
    inline void setFileDescriptor(int fd){_socket_fd = fd; }

    inline int getFileDescriptor(){ return _socket_fd; }
    inline int getLocalPort(){ return _local_port; }
    inline string getLocalIP(){ return _local_ip; }

    inline int getRemotePort(){ return _port; }
    inline string getRemotelIP(){ return _ip; }
    /**
      * \brief writes a string though the socket connection
      * << Function to send a string though the socket connection
      * \param cad string to send
      * \param trials The number of times it tries to send the string before dimissing
      * \return If it succeeds, the function returns the number of bytes, otherwise returns -1
      */
    virtual int write (const string & cad, int trials=1) const throw (char const *) = 0 ;

    /**
      * \brief Reads the incoming data from a socket
      * Reads the Incoming data from a socket
      * \throw String exception when reading is not successful
      * \relates int write (const string & cad, int trials=1);
      * \return the read string
      */
    virtual string read() const throw (char const *) = 0;

    /**
     * @brief open
     * Creates a soket
     * @return filde descriptor of the socket
     */
    virtual int open() throw(char const *) = 0;

    /**
     * @brief close
     * @return True if socket is correctly closed
     */
    bool close();

protected:
    /**
      * \brief Parametrized Constructor.
      * @param fd Socket File Descriptor
      * Protected to avoid instantiation
      */
    AbstractSocket(int fd);


    /**
      * \brief Parametrized Constructor.
      * Protected to avoid instantiation
      */
    AbstractSocket(string rem_ip, int rem_port, string local_ip, int local_port, int fd=0);


    //member variables
    string _ip; //!< Remote IP
    int _port; //!< Remote port

    string _local_ip; //!< Local IP
    int _local_port; //!< Local port

    int _socket_fd; //!< Socket File Descriptor
};

#endif //ABSTRACTSOCKET__H
